#pragma once
#include "common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
using namespace MutexModule;
using namespace LogModule;
using namespace ThreadPoolModule;

static const int backlog = 6;
static const int default_sockfd = -1;
static const int default_nums = 5;

// 翻译模块方法类型
using dict_t = std::function<std::string(std::string, InetAddr)>;

class Serve : public NoCopy
{
private:
    // 定义任务类型
    using task_t = std::function<void()>; // echo serve(线程池方法类型)
private:
    // 多线程模块管理

    class PthreadData // 由于回调方法是静态的无法访问this才要构建PthreadData储存this
    {
    public:
        PthreadData(int fd, InetAddr &ar, Serve *s) : sockfd(fd), addr(ar), tsvr(s)
        {
        }

    public:
        Serve *tsvr;
        int sockfd;
        InetAddr addr;
    };

    // 回调方法（必须是静态 c语言无法传递this)
    static void *Routine(void *args)
    {
        PthreadData *td = static_cast<PthreadData *>(args);
        td->tsvr->Service(td->sockfd, td->addr);
        delete td;
        return nullptr;
    }

public:
    Serve(uint16_t port, dict_t dict_task)
        : _port(port), _is_running(false), _listing_sockfd(default_sockfd), _dict_task(dict_task)
    {
    }

    void Init()
    {
        // 创建套接字
        _listing_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listing_sockfd == -1)
        {
            LOG(LogLevel::FATAL) << "socket fail";
            exit(SOCKET_ERR);
        }

        // 填充addr_in 并绑定套接字
        InetAddr local(_port);
        int n = bind(_listing_sockfd, local.NetAddrPtr(), local.NetAddrLen());
        if (n == -1)
        {
            LOG(LogLevel::FATAL) << "bind fail";
            exit(BIND_ERR);
        }

        // 监听
        n = listen(_listing_sockfd, backlog);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            exit(LISTEN_ERR);
        }
    }

    // 多进程版(适合长服务)
    // void Run()
    // {
    //     _is_running = true;
    //     while (_is_running)
    //     {
    //         struct sockaddr_in peer; // 存储链接端信息
    //         socklen_t peer_len = sizeof(peer);
    //         int sockfd = accept(_listing_sockfd, CONV(peer), &peer_len);
    //         if (_sockfd == -1)
    //         {
    //             LOG(LogLevel::WARNING) << "accept error";
    //             continue;
    //         }

    //         pid_t pid = fork();
    //         // 子进程服务
    //         if (pid == 0)
    //         {
    //             // 关闭子进程不需要的文件描述符
    //             close(_listing_sockfd);

    //             // 进行通信
    //             if (fork() > 0)
    //                 exit(OK);

    //             // 孙子进程执行服务操作做
    //             InetAddr client(peer);
    //             Service(sockfd, client);
    //             close(sockfd); // 关闭客户端套接字
    //             exit(OK);       // 孙子进程退出
    //         }

    //         // 父进程接收链接
    //         if (pid > 0)
    //         {
    //             // 关闭父进程不需要的文件描述符
    //             close(sockfd);
    //             waitpid(pid, nullptr, 0);
    //         }

    //         else
    //         {
    //             LOG(LogLevel::ERROR) << "procrss fail";
    //             exit(FORK_ERR);
    //         }
    //     }

    //     _is_running = false;
    // }

    // 多线程版
    void Run()
    {
        _is_running = true;
        while (_is_running)
        {
            struct sockaddr_in peer; // 存储链接端信息
            socklen_t peer_len = sizeof(peer);
            int sockfd = accept(_listing_sockfd, CONV(peer), &peer_len);
            if (sockfd == -1)
            {
                LOG(LogLevel::WARNING) << "accept error";
                continue;
            }

            InetAddr client(peer);
            // 创建PthreadData对象(不能用智能指针)
            PthreadData *td = new PthreadData(sockfd, client, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, td);
            // 线程分离
            pthread_detach(tid);
        }

        _is_running = false;
    }

    // 线程池版
    // void Run()
    // {
    //     _is_running = true;
    //     while (_is_running)
    //     {
    //         struct sockaddr_in peer; // 存储链接端信息
    //         socklen_t peer_len = sizeof(peer);
    //         int sockfd = accept(_listing_sockfd, CONV(peer), &peer_len);
    //         if (sockfd == -1)
    //         {
    //             LOG(LogLevel::WARNING) << "accept error";
    //             continue;
    //         }

    //         InetAddr client(peer);
    //         ThreadPool<task_t>::GetInstance()->Enqueue([this, sockfd, client]() mutable
    //                                                    {
    //                                                        this->Service(sockfd, client);
    //                                                        close(sockfd); // 在线程内关闭套接字
    //                                                    });
    //     }

    //     _is_running = false;
    // }
    // 服务端接收完客户端请求要给予响应
    void Service(int sockfd, InetAddr &peer)
    {
        while (true)
        {
            char inbuffer[4096];
            ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
            if (n > 0)
            {
                inbuffer[n] = 0;
                std::cout << "[" << peer.StringAddr() << "]" << " say# " << inbuffer << std::endl;

                // std::string echo_string = "tcpserver echo# ";
                // echo_string += inbuffer;

                // 将单词内容及客户端信息发送给上层lambda表达式函数体 使其重载()
                std::string chinese = _dict_task(inbuffer, peer);

                write(sockfd, chinese.c_str(), chinese.size());
            }

            else if (n == 0)
            {
                LOG(LogLevel::INFO) << peer.StringAddr() << "-> " << "关闭";
                break;
            }
            else
            {
                // 异常
                LOG(LogLevel::INFO) << peer.StringAddr() << "-> " << "异常";
                break;
            }
        }
    }

    ~Serve()
    {
        if (_listing_sockfd != default_sockfd)
        {
            close(_listing_sockfd);
        }
    }

private:
    uint16_t _port;
    int _listing_sockfd; // 监听描述符
    bool _is_running;
    dict_t _dict_task; // 翻译方法
};